{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Create a QComponent - Basic"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that you have become familiar with Qiskit Metal and feel comfortable using the available aspects and functionality, the next step is learning how to make your own circuit component in Metal.\n",
    "\n",
    "We will start off by going over the sample `my_qcomponent` in `qiskit_metal>qlibrary>user_components` as a basis, which we will walk through below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reviewing my_qcomponent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# -*- coding: utf-8 -*-\n",
    "\n",
    "# This code is part of Qiskit.\n",
    "#\n",
    "# (C) Copyright IBM 2017, 2021.\n",
    "#\n",
    "# This code is licensed under the Apache License, Version 2.0. You may\n",
    "# obtain a copy of this license in the LICENSE.txt file in the root directory\n",
    "# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.\n",
    "#\n",
    "# Any modifications or derivative works of this code must retain this\n",
    "# copyright notice, and modified files need to carry a notice indicating\n",
    "# that they have been altered from the originals."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Always be sure to include the proper copyright and license information, and give yourself credit for any components you create!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal import draw, Dict\n",
    "from qiskit_metal.toolbox_metal import math_and_overrides\n",
    "from qiskit_metal.qlibrary.core import QComponent"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Import any classes or functions you will be wanting to use when creating your component. The geometries in Metal are shapely objects, which can be readily generated and manipulated through functions in `draw`. Mathematical functions can be accessed via `math_and_overrides`. Any imports that are part of the Metal requirement list can also be used.\n",
    "\n",
    "The key import is what the parent class of your new component will be. For this example, we are using `QComponent` as the parent for `MyQComponent`, which is the base component class in Metal and contains a great deal of automated functionality. All component hierarchy must have QComponent as the top base class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dir(QComponent)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`MyQComponent` creates a simple rectangle of a variable width, height, position and orientation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyQComponent(QComponent):\n",
    "    \"\"\"\n",
    "    Use this class as a template for your components - have fun\n",
    "    \n",
    "    Description:\n",
    "    \n",
    "    Options:\n",
    "    \"\"\"\n",
    "\n",
    "    # Edit these to define your own tempate options for creation\n",
    "    # Default drawing options\n",
    "    default_options = Dict(width='500um',\n",
    "                           height='300um',\n",
    "                           pos_x='0um',\n",
    "                           pos_y='0um',\n",
    "                           orientation='0',\n",
    "                           layer='1')\n",
    "    \"\"\"Default drawing options\"\"\"\n",
    "\n",
    "    # Name prefix of component, if user doesn't provide name\n",
    "    component_metadata = Dict(short_name='component',\n",
    "                             _qgeometry_table_poly='True')\n",
    "    \"\"\"Component metadata\"\"\"\n",
    "    \n",
    "    def make(self):\n",
    "        \"\"\"Convert self.options into QGeometry.\"\"\"\n",
    "\n",
    "        p = self.parse_options()  # Parse the string options into numbers\n",
    "\n",
    "        # EDIT HERE - Replace the following with your code\n",
    "        # Create some raw geometry\n",
    "        # Use autocompletion for the `draw.` module (use tab key)\n",
    "        rect = draw.rectangle(p.width, p.height, p.pos_x, p.pos_y)\n",
    "        \n",
    "        rect = draw.rotate(rect, p.orientation)\n",
    "        rect = draw.translate(rect,p.pos_x,p.pos_y)\n",
    "        \n",
    "        geom = {'my_polygon': rect}\n",
    "        self.add_qgeometry('poly', geom, layer=p.layer, subtract=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The docstring at the start of the class should clearly explain what the component is, what the parameterized values of the component refer to (in a sense the 'inputs'), and any other information you believe would be relevant for a user making use of your component.\n",
    "\n",
    "`default_options` is a dictionary to be included in the class of all components. The keywords, of type string, in the default dictionary are the parameters the front-end user is allowed to modify. The keywords in the above indicate that the width and height can be modified via the components options, but have a default value of 500um and 300 um respectively. Further, the position and orientation can also be changed. The `layer` is an expected keyword in a default dictionary, as it is used by renderers to help determine further properties of the `qgeometry` of the component when rendered, eg. GDS QRenderer uses the layer # to define which layer the qgeometry is on.\n",
    "\n",
    "`component_metadata` is a dictionary which contains some important pieces of information, such as the default/shorthand name of the component (`short_name`), or indicating what types of qgeometry tables are included in this component, eg. `_qgeometry_table_poly='True'`.\n",
    "The `component_metadata` must contain the flags for each type of qgeometry table being used via `add_qgeometry` methods at the end of the `make()` function, in order for renderer options to be updated correctly. Currently the options are:\n",
    "\n",
    "`_qgeometry_table_path='True'`\n",
    "\n",
    "`_qgeometry_table_poly='True'`\n",
    "\n",
    "`_qgeometry_table_junction='True'`\n",
    "\n",
    "\n",
    "The `make()` method is where the actual generation of the component's layout is written. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The make() method"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Although not required, a good first line is `p = self.parse_options()` to cut down on your amount of typing. The `parse_options()` translates the keywords in `self.options` from strings into their appropriate value with respect to the prefix included, e.g.,`p.width`=> \"500um\" -> 0.0005\n",
    "\n",
    "Following this, all code generating the shapely geometries that are to represent your circuit layout should be written, via the `draw` module or even written in directly. It is a good practice to play around with the geometries in a jupyter notebook first for quick visual feedback, such as:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "draw.rectangle(1,2,0,0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "draw.rotate(draw.rectangle(1,2,0,0), 45)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or for a little more complexity:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "face = draw.shapely.geometry.Point(0, 0).buffer(1)\n",
    "eye = draw.shapely.geometry.Point(0, 0).buffer(0.2)\n",
    "eye_l = draw.translate(eye, -0.4, 0.4)\n",
    "eye_r = draw.translate(eye, 0.4, 0.4)\n",
    "\n",
    "smile = draw.shapely.geometry.Point(0, 0).buffer(0.8)\n",
    "cut_sq = draw.shapely.geometry.box(-1, -0.3, 1, 1)\n",
    "smile = draw.subtract(smile, cut_sq)\n",
    "face = draw.subtract(face, smile)\n",
    "face = draw.subtract(face, eye_r)\n",
    "face = draw.subtract(face, eye_l)\n",
    "face"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once you are happy with your geometries, and have them properly parameterized to allow the Front End User as much customization of your component as you wish, it is time to convert the geometries into Metal `qgeometries` via `add_qgeometry`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### add_qgeometry"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import qiskit_metal as metal\n",
    "?metal.qlibrary.core.QComponent.add_qgeometry"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`add_qgeometry` is the method by which the shapely geometries you have drawn are converted into Metal qgeometries, the format which allows for the easy translatability between different renderers and the variable representation of quantum elements such as Josephson junctions.\n",
    "\n",
    "Currently there are three kinds of qgeometries, `path`, `poly` and `junction`.\n",
    "`path` -> shapely LineString\n",
    "`poly` -> any other shapely geometry (currently)\n",
    "`junction` -> shapely LineString\n",
    "\n",
    "Both `path` and `junction` also take and input of `width`, with is added to the qgeometry table to inform renderers of, as an example, how much to buffer the LineString of a cpw transmission line to turn it into a proper 2D sheet.\n",
    "\n",
    "`subtract` indicates this qgeometry is to be subtracted from the ground plane of that layer#. A ground plane is automatically included for that layer at the dimension of the chip size if any qgeometry has `subtract = True`. As an example, a cpw transmission line's dielectric gap could be drawn by using the same LineString as previously, having the `width = cpw_width + 2*cpw_gap` and setting `subtract = True`.\n",
    "\n",
    "`fillet` is an option that informs a renderer that the vertices of this qgeometry are to be filleted by that value (eg. `fillet = \"100um\"`). "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### add_pin"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "?metal.qlibrary.core.QComponent.add_pin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The final step for creating your QComponent is adding of pins. This is not necessarily a requirement for your component, but to have full functionality with Metal and be able to make use of auto-routing components with it, you will want to indicate where the \"ports\" of your component are.\n",
    "\n",
    "Following from the above docstring, pins can be added from two coordinates indicating either an orthogonal vector to the port plane of your component, or a tangent to the port plane of your component. For the former, you want the vector to be pointing to the middle point of your intended plane, with the latter being across the length of your intended plane (as indicated in the above figure). The `width` should be the size of the plane (say, in the case of a CPW transmission line, the trace width), with the `gap` following the same logic (though this value can be ignored for any non-coplanar structure). "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "Below is a simple QComponent that implements everything we have reviewed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal import draw, Dict\n",
    "from qiskit_metal.toolbox_metal import math_and_overrides\n",
    "from qiskit_metal.qlibrary.core import QComponent\n",
    "\n",
    "class MySimpleGapCapacitor(QComponent):\n",
    "    \"\"\"\n",
    "    Inherits 'QComponent' class.\n",
    "    \n",
    "    Description:\n",
    "        A simple CPW style gap capacitor, with endcap islands each coupled to their own\n",
    "        cpw transmission line that ends in a pin.\n",
    "    \n",
    "    Options:\n",
    "        * cpw_width: width of the cpw trace of the transmission line\n",
    "        * cpw_gap: dielectric gap of the cpw transmission line\n",
    "        * cap_width: width of the gap capacitor (size of the charge islands)\n",
    "        * cap_gap: dielectric space between the two islands\n",
    "        * pos_x/_y: position of the capacitor on chip\n",
    "        * orientation: 0-> is parallel to x-axis, with orientation (in degrees) counterclockwise.\n",
    "        * layer: the layer number for the layout \n",
    "        \n",
    "    \n",
    "    \"\"\"\n",
    "\n",
    "    # Edit these to define your own tempate options for creation\n",
    "    # Default drawing options\n",
    "    default_options = Dict(cpw_width='15um',\n",
    "                           cpw_gap='9um',\n",
    "                           cap_width='35um',\n",
    "                           cap_gap='3um',\n",
    "                           pos_x='0um',\n",
    "                           pos_y='0um',\n",
    "                           orientation='0',\n",
    "                           layer='1')\n",
    "    \"\"\"Default drawing options\"\"\"\n",
    "\n",
    "    # Name prefix of component, if user doesn't provide name\n",
    "    component_metadata = Dict(short_name='component', \n",
    "                             _qgeometry_table_poly='True',\n",
    "                             _qgeometry_table_path='True')\n",
    "    \"\"\"Component metadata\"\"\"\n",
    "    \n",
    "    def make(self):\n",
    "        \"\"\"Convert self.options into QGeometry.\"\"\"\n",
    "\n",
    "        p = self.parse_options()  # Parse the string options into numbers\n",
    "\n",
    "        pad = draw.rectangle(p.cpw_width, p.cap_width, 0, 0)\n",
    "        pad_left = draw.translate(pad,-(p.cpw_width+p.cap_gap)/2,0)\n",
    "        pad_right = draw.translate(pad,(p.cpw_width+p.cap_gap)/2,0)\n",
    "        pad_etch = draw.rectangle(2*p.cpw_gap+2*p.cpw_width+p.cap_gap,2*p.cpw_gap+p.cap_width)\n",
    "        cpw_left = draw.shapely.geometry.LineString([[-(p.cpw_width+p.cap_gap/2),0],[-(p.cpw_width*3 +p.cap_gap/2),0]])\n",
    "        cpw_right = draw.shapely.geometry.LineString([[(p.cpw_width+p.cap_gap/2),0],[(p.cpw_width*3 +p.cap_gap/2),0]])\n",
    "        \n",
    "        geom_list = [pad_left,pad_right,cpw_left,cpw_right,pad_etch]\n",
    "        geom_list = draw.rotate(geom_list,p.orientation)\n",
    "        geom_list = draw.translate(geom_list,p.pos_x,p.pos_y)\n",
    "        [pad_left,pad_right,cpw_left,cpw_right,pad_etch] = geom_list\n",
    "\n",
    "        self.add_qgeometry('path', {'cpw_left':cpw_left, 'cpw_right':cpw_right}, layer=p.layer, width = p.cpw_width)\n",
    "        self.add_qgeometry('path', {'cpw_left_etch':cpw_left, 'cpw_right_etch':cpw_right}, layer=p.layer, width = p.cpw_width+2*p.cpw_gap, subtract=True)\n",
    "        self.add_qgeometry('poly', {'pad_left':pad_left, 'pad_right':pad_right}, layer=p.layer)\n",
    "        self.add_qgeometry('poly', {'pad_etch':pad_etch}, layer=p.layer, subtract=True)\n",
    "        \n",
    "        self.add_pin('cap_left', cpw_left.coords, width = p.cpw_width, gap = p.cpw_gap, input_as_norm=True)\n",
    "        self.add_pin('cap_right', cpw_right.coords, width = p.cpw_width, gap = p.cpw_gap, input_as_norm=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design = metal.designs.DesignPlanar()\n",
    "\n",
    "gui = metal.MetalGUI(design)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_cap = MySimpleGapCapacitor(design,'my_cap')\n",
    "gui.rebuild()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should now see *my_cap* in the Metal gui. One can work on the layout of the component through these cells by changing the above class, such as how the parameterized values are used. By enabling `overwrite_enabled` (which should normally be kept to False), the code can quickly be iterated through until you, the component designer, is happy with the qcomponent you have just created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design.overwrite_enabled = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will delve into more complex QComponent topics in the next notebook, `Creating a QComponent - Advanced` </br>\n",
    "\n",
    "Use the command below to close Metal GUI."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gui.main_window.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
